# ===================================================================================
#
# Microsoft PowerShell Source File
#
# NAME: KaseyaCMD - Main Module
#
# ORIGINAL AUTHOR: Chris Whitfield
# ORIGIN DATE: June 29th, 2010 - 1756 hours central time
#
# COMMENT: Primary module that initiates connection to Kaseya, provides help, and 
#		   loads all sub-modules.
#
# EDIT AUTHOR: Chris Whitfield
# EDIT DATE: July 19th, 2010 - 0800 hours central time
# 
# CHANGE NOTES:
#	- Completed update of naming changes to KaseyaCMD
#	- Updated structure to better align with Kaseya
#	- Updated commands to match framework and provide consistency
#	- Changed help type from in-line to XML based for easier editing
#
# ===================================================================================

# -----------------------------------------------------------------------------------
# Default run function - runs when some base cmdlets are executed without parameters
# as well as when module is loaded or when there is an error
# -----------------------------------------------------------------------------------
function WriteResult([string]$kcmdmsg, [boolean]$kcmdstatus, [string]$kcmderrmsg) {
	
	if ($kcmdstatus -eq $false) { 
		Write-Error -Message $kcmdmsg -Exception $kcmderrmsg 
	}Elseif($kcmdstatus -eq $true) {
		Write-Host $kcmdmsg -ForegroundColor Green
	}
	
	$usagetxt = @"

To get a list of available commands specific to the KaseyaCMD module, simply type:

	Get-KCMDCommand
	
To get your Kaseya Instance, simply type:

	Get-KCMDServer hostname

By default, all modules are loaded. Eventually you will be able to specify preferences 
as to which modules you wish to load directly from your profile. In the meantime, you
can load specific sub-modules by specifying them individually. The sub-modules are as
follows:

	KCMD.Agent
		Provides agent focused cmdlets; Get-KCMDAgent, New-KCMDAgentInstallPackage, etc
	KCMD.System
		Provides system level cmdlets; Get-KCMDUser, New-KCMDOrg, Add-KCMDRole, etc
	KCMD.Monitor
		Provides monitoring focused cmdlets; Get-KCMDAlarm, Close-KCMDAlarmt, etc
	KCMD.Ticket
		Provides ticketing focused cmdlets; Get-KCMDTicket, Update-KCMDTicket, etc

Note: All sub-modules are dependant upon the main KaseyaCMD module as it provides the
authentication component. To get a list of all available cmdlets for a specific sub-
module, use either the Get-Command or Get-KCMDCommand with the 'module' parameter.
	
"@ 

	if(!($runfullonce)){ 
		Write-Host "Module Loaded - $usagetxt" -ForegroundColor Yellow
		$runfullonce = $true
	}
} # End WriteResult

# -----------------------------------------------------------------------------------
# Gets list of KCMD specific commands
# -----------------------------------------------------------------------------------
function Get-KCMDCommand {
	[CmdletBinding()]
	param(
		[Parameter(Position=0)]
		[string]$name = "*",
		[Parameter()]
		[string]$module = "KaseyaCMD";
		[Parameter()]
		[string]$verb = "*",
		[Parameter()]
		[string]$noun = "*"
	)
	
	Process
	{
		$reg-fullmodname = "(^kcmd)+(?=\.(agent|system|monitor|ticket)$)"
		$reg-partmodname = "(agent|system|monitor|ticket)"
		$reg-defmodname = "KaseyaCMD"

		$modlist = @"
The available sub-modules for KaseyaCMD are as follows:
	
	System
	Agent
	Monitor
	Ticket

Note: If using the standard Get-Command cmdlet, you must preface the above with 'KCMD.' 
when filtering output using the -Module switch. The use of this prefix becomes optional
however when using the Get-KaseyaCMD cmdlet as it is assumed.
"@

		if(!($module -match $reg-fullmodname -OR $module -match $reg-partmodname -OR $module -eq $reg-defmodname)){
			Write-Host $modlist -ForegroundColor Green
		}Else{
			if($module -match $reg-partmodname){
				$module = "KCMD.$module"
			} 
				
			Get-Command -Module $module -Name $name -Verb $verb -Noun $noun 
		}
	}
	
} # End Get-KCMDCommand

# -----------------------------------------------------------------------------------
# Gets connection to specified Kaseya server
# -----------------------------------------------------------------------------------
function Get-KCMDServer {
	[CmdletBinding()]
	param(
		[Parameter(Position=0)]
		[string]$KServer = (Read-Host "Please specify your Kaseya URL:"),
		[Parameter()]
		[string]$User = (Read-Host "Please specify a username to authenticate with:"),
		[Parameter()]
		[string]$Password = (Read-Host "Please specify a password:" -assecurestring,
		[Parameter()]
		[string]$Domain = $null
	)
	
	# Check username for presence of domain with '\' using regular expression
	if($User -match "\w\\\w"){
		# Update user variable to correct format
		$User = $User.Replace("\","/")
	}

	# Check for value in Domain and update User variable
	if(!($Domain -eq $null)){
		$User = "$Domain/$User"
	}

	# Check for secure string from 'Read-Host' and decrypt for use if required
	# Note: This is required so we can re-encrypt using hash.dll for Kaseya
	if($($password.GetType()).Name -eq 'SecureString'){
		# Decrypt password for use
		$ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($password)
		$str = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)

		# Update password variable to unencrypted value 
		$password = $str

		# Release unmanaged memory
		[System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($ptr)
	}

	# Create hash of password
	$KaseyaHash = New-Object Kaseya.Hash
	[string]$RandomNumber = $KaseyaHash.HashToCoveredPassword($User, [REF]$Password)
	
	# Bind to Web Service on Kaseya installation
	$KaseyaWSDL = "$KServer/vsaWs/kaseyaWs.asmx?WSDL"
	$Global:KaseyaInst = New-WebServiceProxy -Uri $KaseyaWSDL -Namespace KaseyaWS
	
	# Create an authentication request
	$Global:KaseyaAuthReq = New-Object KaseyaWS.AuthenticationRequest
	$KaseyaAuthReq.UserName = $User
	$KaseyaAuthReq.RandomNumber = $RandomNumber
	$KaseyaAuthReq.CoveredPassword = $Password

	# Submit authentication request to server and store response
	$KaseyaAuthResp = $KaseyaInst.Authenticate($KaseyaAuthReq)
	
	# Store last transaction
	$Global:KaseyaLastTransaction = Get-KCMDTransaction
	$Global:KaseyaTransHistory += $KaseyaLastTransaction

	# Check for a valid session ID
	if($KaseyaAuthResp.SessionID -ne 0){
		$Global:KaseyaSessionID = $KaseyaAuthResp.SessionID.ToString()
		WriteResult -kcmdmsg "You have successfully authenticated to Kaseya!" -kcmdstatus $true
	}Else{
		WriteResult -kcmdmsg "Connection to Kaseya failed!" -kcmdstatus $false -kcmderrmsg $($KaseyaAuthResp.ErrorMessage)
	}
} # End Get-KCMDServer


# -----------------------------------------------------------------------------------
# Gets published view details
# -----------------------------------------------------------------------------------
Function Get-KCMDDBView {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$false,ValueFromPipeline=$true,Position=0)]
		[string]$Name,
		[Parameter()]
		[switch]$columns
	)

	# Create a public views request
	$KaseyaPubViewReq = New-Object KaseyaWS.GetPublishedViewsRequest
	$KaseyaPubViewReq.SessionID = $KaseyaSessionID

	# Create a public view columns request
	$KaseyaPubViewColReq = New-Object KaseyaWS.GetPublishedViewColumnsRequest
	$KaseyaPubViewColReq.SessionID = $KaseyaSessionID

	# Submit view request to server and store response
	$KaseyaPubViewRes = $KaseyaInst.GetPublishedViews($KaseyaPubViewReq)

	# Store last transaction
	$Global:KaseyaLastTransaction = Get-KCMDTransaction
	$Global:KaseyaTransHistory += $KaseyaLastTransaction

	if($KaseyaPubViewRes.ErrorMessage){
		WriteResult -kcmdmsg "Command failed!" -kcmdstatus $false -kcmderrmsg $($KaseyaPubViewRes.ErrorMessage)
	}Else{
		$KaseyaPubViews = $KaseyaPubViewRes.PublishedViews

		# Check for Name and update results if present
		if($Name){
			Foreach($n in $Name){
				$KaseyaViews += $KaseyaPubViews | Where-Object { $_.viewName -like $n }
			}
		}Else{
			$KaseyaViews = $KaseyaPubViews
		}

		# Create placeholder for output
		$KaseyaViewDetails = @()

		Foreach($KView in $KaseyaViews){
			$KaseyaPubViewColReq.viewName = $KView.viewName
			$KaseyaPubViewColRes = $KaseyaInst.GetPublishedViewColumns($KaseyaPubViewColReq)

			$KaseyaView = New-Object PSObject -Property @{
				ViewName		= $KView.viewName
				ViewColumns		= $KaseyaPubViewColRes.PublishedViewColumns
			}

			# Add current custom object to placeholder hash table
			$KaseyaViewDetails += $KaseyaView

			# Store last transaction
			$Global:KaseyaLastTransaction = Get-KCMDTransaction
			$Global:KaseyaTransHistory += $KaseyaLastTransaction

		}

		# Check for 'columns' switch and expand results if present
		if($columns){
			Foreach($kvd in $KaseyaViewDetails){
				Write-Host @"View Name: $kvd.ViewName"
Published Columns:
$kvd.ViewColumns
"@
			}
		}Else{
			# If no 'columns' switch, just output the custom object
			Write-Output $KaseyaViewDetails
		}
	}

} # End Get-KCMDView

# -----------------------------------------------------------------------------------
# Gets published view data
# -----------------------------------------------------------------------------------
Function Get-KCMDViewData {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true,Position=0)]
		[string]$ViewName,
		[Parameter()]
		[string]$filter
	)

	# Create a public view rows request
	$KaseyaPubViewRowReq = New-Object KaseyaWS.GetPublishedViewRowsRequest
	$KaseyaPubViewRowReq.SessionID = $KaseyaSessionID
	$KaseyaPubViewRowReq.viewName = $ViewName

	if($filter -ne $null){
		$KaseyaPubViewRowReq.whereClause = $filter
	}

	# Get results
	$KaseyaPubViewRowRes = $KaseyaInst.GetPublishedViewRows($KaseyaPubViewRowReq)
	[XML]$KaseyaPubViewData = $KaseyaPubViewRowRes.PublishedViewRows
	$RowData = $KaseyaPubViewData.$ViewName.row 

	# Store last transaction
	$Global:KaseyaLastTransaction = Get-KCMDTransaction
	$Global:KaseyaTransHistory += $KaseyaLastTransaction

	# Output results
	Write-Output $RowData

} # End Get-KCMDViewData

# -----------------------------------------------------------------------------------
# Gets transaction details and history
# -----------------------------------------------------------------------------------
Function Get-KCMDTransaction {
	[CmdletBinding()]
	param(
		[Parameter(Position=0)]
		[int]$TransID,
		[Parameter()]
		[switch]$History
	)

	if($History){
		$KaseyaTransHistory
	}Else{
		# Create LogEntryRequest
		$KaseyaLogEntryReq = New-Object KaseyaWS.GetLogEntryRequest
		$KaseyaLogEntryReq.SessionID = $KaseyaSessionID

		# Check for transaction ID and add to request if present
		if($TransID){
			$KaseyaLogEntryReq.TransactionID = $TransID
		}

		# Submit log entry request to server and store response
		$KaseyaLogEntryRes = $KaseyaInst.GetLogEntry($KaseyaLogEntryReq)

		# Return result
		Return $KaseyaLogEntryRes
	}

} # End Get-KCMDTransaction

# Set runfullonce to false 
$runfullonce = $false

# Create placeholder for transaction history
$Global:KaseyaTransHistory = @()

$ Print module load result
WriteResult